package movimentar;

import java.util.LinkedList;
import java.util.PriorityQueue;

import meu.Jogo;

import pos.Posicao;

public class Trajecto {

	private Jogo jogo;
	private final LinkedList<Posicao> mapa;
	private final Posicao start;
	private final Posicao target;
	private PriorityQueue<Posicao> open;
	private PriorityQueue<Posicao> closed;

	public Trajecto(Jogo jogo, LinkedList<Posicao> mapa, Posicao start,
			Posicao target) {
		this.jogo = jogo;
		this.mapa = mapa;
		this.start = start;
		this.target = target;
	}

	public LinkedList<Posicao> calcPath() {
		LinkedList path = new LinkedList<Posicao>();
		open = new PriorityQueue<Posicao>();
		closed = new PriorityQueue<Posicao>();
		start.setCost(Math.abs(target.getX() - start.getX())
				+ Math.abs(target.getY() - start.getY()));
		open.add(start);
		while (open.peek() != target && !open.isEmpty()) {
			Posicao current = open.poll();
			closed.add(current);
			// Determinar os vizinhos da casa current
			Posicao norte = null, este = null, sul = null, oeste = null;
			if (current.getY() > 0)
				norte = jogo.obterPosicao(current.getX(), current.getY() - 1);
			if (current.getX() < 19)
				este = jogo.obterPosicao(current.getX() + 1, current.getY());
			if (current.getX() > 0)
				oeste = jogo.obterPosicao(current.getX() - 1, current.getY());
			if (current.getY() < 19)
				sul = jogo.obterPosicao(current.getX(), current.getY() + 1);
			Posicao[] viz = { norte, este, sul, oeste };
			double dist2 = current.getDist() + 1.0;
			for (Posicao vizinho : viz) {
				if (vizinho == null) {
					continue;
				}
				if (vizinho.getTipo() > 2) {
					continue;
				}
				if (open.contains(vizinho) && dist2 < vizinho.getDist()) {
					open.remove(vizinho);
					vizinho.setDist(0);
					vizinho.setCost(0);
					vizinho.setFather(null);
				}
				if (closed.contains(vizinho) && dist2 < vizinho.getDist()) {
					closed.remove(vizinho);
					vizinho.setDist(0);
					vizinho.setCost(0);
					vizinho.setFather(null);
				}
				if (!open.contains(vizinho) && !closed.contains(vizinho)) {
					// Calcular a heuristica
					double h = Math.abs(target.getX() - vizinho.getX())
							+ Math.abs(target.getY() - vizinho.getY());
					vizinho.setDist(dist2);
					vizinho.setCost(dist2 + h);
					vizinho.setFather(current);
					open.add(vizinho);
				}
			}
		}
		// Reconstruir a path a partir do target.
		if (target.getFather() != null) {
			path.add(target);
			Posicao current = target;
			while (current.getFather() != start) {
				path.add(current.getFather());
				current = current.getFather();
				current.setTipo(4);
			}
			return path;
		} else {
			return null;
		}
	}
}
